[Rust] 高速キャッシュサービス Momentoを使ってみる
Introduction
Momentoは、クラウドネイティブな
高速のサーバーレスキャッシュサービスです。
キャッシュサーバの設定や準備は短時間(数分)で完了し、
キャッシュ最適化・スケール・管理も自動。
セキュリティもデフォルトでしっかりしています。(E2E暗号化や監査ログサポートなど)
公式サイトでは「世界最速」を謳っていますが、実際はどんな感じでしょうか。
今回はRustを使ってMomentoにアクセスしてみます。
Environment
- OS : MacOS 12.4
- rust : 1.61.0
M1 Macで動かしました。
AWSアカウントはセットアップ済みとします。
Setup
Momentoのセットアップは公式Githubや以前の記事などを参考におこなってください。
ここにあるように、
momento account signupで指定したメールアドレス宛にトークンが送付されているはずです。
このトークンはMomento CLIセットアップや
このあとプログラムからアクセスするために必要なので、確認しておきましょう。
momentoコマンドを実行してversionが表示できればOKです。
% momento --version momento 0.20.1
そしてRustのインストール。
% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
RustとCargoのコマンドが使えることを確認。
% rustup --version rustup 1.24.3 (ce5817a94 2021-05-31) info: This is the version for the rustup toolchain manager, not the rustc compiler. info: The currently active `rustc` version is `rustc 1.61.0 (fe5b13d68 2022-05-18)` % cargo --version cargo 1.61.0 (a028ae42f 2022-04-29)
Lambdaのビルド&デプロイを簡単にするため、Cargo Lambdaをインストールします。
% cargo install cargo-lambda
Introduce Momento Library
各種Momentoライブラリの使い方はシンプルです。
ここを参考に、
RustでMomentoライブラリを使う方法をみてみましょう。
Momentoライブラリは、
Cargo.tomlに下記依存ライブラリを追記するだけでOKです。
[dependencies] momento = "0.6.0"
ちなみにここにあるサンプルの場合、
tokioも追加する必要があります。
RustでMomentoにアクセス
クライアントを作成するためにSimpleCacheClientBuilderを使います。
tokenとttlを指定してクライアントを作り、
create_cacheでキャッシュを作成します。
let auth_token = "your token"; let item_default_ttl_seconds = 300; let mut cache_client = SimpleCacheClientBuilder::new( auth_token, NonZeroU64::new(item_default_ttl_seconds).unwrap(), ) .unwrap() .build(); let cache_name = String::from("your-cache-name"); match cache_client.create_cache(&cache_name).await { Ok(_) => { println!("create_cache OK!"); } Err(err) => { eprintln!("{}", err); } }
Rust用Momentoライブラリでは、キャッシュ関連操作はすべて非同期なので、
create_cache時にawaitを使います。
ちなみに、キャッシュを削除したいときは
cache_client.delete_cacheとすればOK。
作成したキャッシュに対してデータの保存/取得/削除をするのも簡単です。
クライアントの各種関数に、さきほど作ったキャッシュの参照と
データのkeyやvalueを渡します。
//キャッシュデータの保存 let key = String::from("my_key"); let value = String::from("my_value"); cache_client .set(&cache_name, key.clone(), value.clone(), None) .await .unwrap(); //キャッシュデータの取得 cache_client .get(&cache_name, key.clone()) .await .unwrap(); //キャッシュデータの削除 cache_client .delete(&cache_name, key.clone()) .await .unwrap();
getは正常に処理が行われた場合、MomentoGetResponseを返します。
MomentoGetResponseはresult(キャッシュヒットしたか判定するenum)と
value(実際の値の&[u8])をもっています。
なので、例えば文字列をsetして、キャッシュからgetして使いたい場合は↓のようにします。
let result:MomentoGetResponse = cache_client.get(&cache_name, key.clone()).await.unwrap(); println!("{:?}",String::from_utf8(result.value).unwrap());
Create AWS Lambda on Rust
次は、AWS Lambda on RustでMomentoをつかってみましょう。
Lambdaでも、ローカルで動かすのと特に違いはありません。
まずはCargo Lambdaでプロジェクトの作成。
簡単に実行できるように、HTTP functionで作る。
% cargo lambda new momento-lambda Is this function an HTTP function? <yes>
momento-lambda/Cargo.tomlに依存ライブラリを追加。
[dependencies] ・・・ quanta = "0.10.0" momento = "0.6.0"
momento-lambda/src/main.rsにMomento関連の処理を追記します。
キャッシュをset/get/deleteして処理時間を計測し、それらをログに出力します。
use lambda_http::{run, service_fn, Error, IntoResponse, Request, RequestExt, Response}; use quanta::Clock; use momento::response::cache_get_response::MomentoGetStatus; use momento::simple_cache_client::SimpleCacheClientBuilder; use std::num::NonZeroU64; use std::process; async fn function_handler(event: Request) -> Result<impl IntoResponse, Error> { let clock = Clock::new(); const N:u32 = 1_000_000; let start = clock.now(); let mut stop = start; let auth_token = "<your Momento Token>".to_string(); let item_default_ttl_seconds = 60; let mut cache_client = match SimpleCacheClientBuilder::new( auth_token, NonZeroU64::new(item_default_ttl_seconds).unwrap(), ) { Ok(client) => client, Err(err) => { eprintln!("{}", err); panic!("create cache_client error") } } .build(); // Creating a cache named "cache" let cache_name = String::from("cache"); match cache_client.create_cache(&cache_name).await { Ok(_) => { println!("create_cache OK!") } Err(err) => { eprintln!("{}", err); panic!("create_cache error") } } // cache key let key = String::from("my_key"); // cache value let value = String::from("my_value"); println!("Setting key: {}, value: {}", key, value); match cache_client .set(&cache_name, key.clone(), value.clone(), None) .await { Ok(_) => {} Err(err) => { eprintln!("{}", err); } }; //get cache value match cache_client.get(&cache_name, key.clone()).await { Ok(r) => match r.result { MomentoGetStatus::HIT => println!("cache hit!"), MomentoGetStatus::MISS => println!("cache miss"), _ => println!("error occurred"), }, Err(err) => { eprintln!("{}", err); } }; // delete cache match cache_client.delete_cache(&cache_name).await { Ok(_) => { println!("Permanently deleted cache named, {}", cache_name); } Err(err) => { eprintln!("{}", err); } }; //Execution Time Measurement stop = clock.now(); println!("quanta::clock::now() overhead = {:?}",stop.duration_since(start)); let resp = Response::builder() .status(200) .header("content-type", "text/html") .body("Hello AWS Lambda HTTP request") .map_err(Box::new)?; Ok(resp) } #[tokio::main] async fn main() -> Result<(), Error> { tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .without_time() .init(); run(service_fn(function_handler)).await }
ファイルが修正できたらビルド&デプロイ。
% cd momento-lambda % cargo lambda build % cargo lambda deploy --enable-function-url momento-lambda --iam-role <iamロールのArn> ? function arn: arn:aws:lambda:XXXXXXXXXXXXXXXXXXX function url: https://somethingurl.lambda-url.us-east-1.on.aws/
Lambda実行後にログをみてみると、Momentoにアクセスできているのがわかります。
Summary
今回はサーバレスキャッシュサービスMomentoをRustから使ってみました。
セットアップも使い方も簡単ですし、Rust以外にも
JavaScript、Python、Java、Go、C#にライブラリが用意されています。
基本的な使い方は同じなので、お好みの環境で試してみてください。